from django.shortcuts import render, get_object_or_404, redirect
from django.views import generic
from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin
from django.contrib.auth.decorators import login_required, permission_required
from django.http import HttpResponseRedirect, JsonResponse
from django.urls import reverse, reverse_lazy
from django.views.decorators.http import require_POST
from django.db.models import Count, Avg, Q
from django.contrib import messages
from .models import Book, Author, BookInstance, Genre, Review, UserProfile, BorrowHistory
from .forms import RenewBookForm, AuthorForm, BookForm, ReviewForm, UserProfileForm, UserForm, SearchForm, RegisterForm
from django.views.generic.edit import CreateView, UpdateView, DeleteView
import datetime

def index(request):
    """网站主页视图"""
    # 生成一些主要对象的计数
    num_books = Book.objects.all().count()
    num_instances = BookInstance.objects.all().count()
    # 可用的书
    num_instances_available = BookInstance.objects.filter(status__exact='a').count()
    num_authors = Author.objects.count()
    
    # 会话计数器
    num_visits = request.session.get('num_visits', 0)
    request.session['num_visits'] = num_visits + 1
    
    # 获取评分最高的书籍
    top_rated_books = Book.objects.annotate(avg_rating=Avg('review__rating')).order_by('-avg_rating')[:5]
    
    # 获取最近添加的书籍
    latest_books = Book.objects.all().order_by('-id')[:5]
    
    # 获取借阅排行榜
    popular_books = Book.objects.annotate(borrow_count=Count('bookinstance__borrowhistory')).order_by('-borrow_count')[:5]
    
    context = {
        'num_books': num_books,
        'num_instances': num_instances,
        'num_instances_available': num_instances_available,
        'num_authors': num_authors,
        'num_visits': num_visits,
        'top_rated_books': top_rated_books,
        'latest_books': latest_books,
        'popular_books': popular_books,
    }
    
    return render(request, 'index.html', context=context)

class BookListView(generic.ListView):
    model = Book
    paginate_by = 10
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['search_form'] = SearchForm(self.request.GET or None)
        return context
    
    def get_queryset(self):
        queryset = Book.objects.all()
        form = SearchForm(self.request.GET or None)
        
        if form.is_valid():
            query = form.cleaned_data.get('query')
            genre = form.cleaned_data.get('genre')
            rating = form.cleaned_data.get('rating')
            
            if query:
                queryset = queryset.filter(
                    Q(title__icontains=query) | 
                    Q(author__first_name__icontains=query) |
                    Q(author__last_name__icontains=query) |
                    Q(summary__icontains=query)
                )
            
            if genre:
                queryset = queryset.filter(genre=genre)
            
            if rating:
                queryset = queryset.annotate(avg_rating=Avg('review__rating')).filter(avg_rating__gte=rating)
        
        return queryset
    
class BookDetailView(generic.DetailView):
    model = Book
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        book = self.get_object()
        
        # 添加评论表单
        context['review_form'] = ReviewForm()
        
        # 获取用户的评论
        if self.request.user.is_authenticated:
            context['user_review'] = Review.objects.filter(book=book, user=self.request.user).first()
            context['user_has_favorited'] = book.favorites.filter(id=self.request.user.id).exists()
            context['user_has_liked'] = book.likes.filter(id=self.request.user.id).exists()
        
        # 获取相似书籍
        similar_books = Book.objects.filter(genre__in=book.genre.all()).exclude(id=book.id).distinct()
        context['similar_books'] = similar_books[:4]
        
        return context

class AuthorListView(generic.ListView):
    model = Author
    paginate_by = 10

class AuthorDetailView(generic.DetailView):
    model = Author

class LoanedBooksByUserListView(LoginRequiredMixin, generic.ListView):
    """已登录用户借的书视图"""
    model = BookInstance
    template_name = 'catalog/bookinstance_list_borrowed_user.html'
    paginate_by = 10
    
    def get_queryset(self):
        return (
            BookInstance.objects.filter(borrower=self.request.user)
            .filter(status__exact='o')
            .order_by('due_back')
        )

class AllBorrowedBooksListView(PermissionRequiredMixin, generic.ListView):
    """显示所有借出的书（仅管理员可见）"""
    model = BookInstance
    permission_required = 'catalog.can_view_all_borrowed'
    template_name = 'catalog/bookinstance_list_borrowed_all.html'
    paginate_by = 10
    
    def get_queryset(self):
        return BookInstance.objects.filter(status__exact='o').order_by('due_back')

@login_required
@permission_required('catalog.can_mark_returned', raise_exception=True)
def renew_book_librarian(request, pk):
    """续借图书功能"""
    book_instance = get_object_or_404(BookInstance, pk=pk)
    
    if request.method == 'POST':
        form = RenewBookForm(request.POST)
        
        if form.is_valid():
            book_instance.due_back = form.cleaned_data['renewal_date']
            book_instance.save()
            
            return HttpResponseRedirect(reverse('all-borrowed'))
    else:
        proposed_renewal_date = datetime.date.today() + datetime.timedelta(weeks=3)
        form = RenewBookForm(initial={'renewal_date': proposed_renewal_date})
    
    context = {
        'form': form,
        'book_instance': book_instance,
    }
    
    return render(request, 'catalog/book_renew_librarian.html', context)

class AuthorCreate(PermissionRequiredMixin, CreateView):
    model = Author
    form_class = AuthorForm
    permission_required = 'catalog.can_mark_returned'
    
class AuthorUpdate(PermissionRequiredMixin, UpdateView):
    model = Author
    form_class = AuthorForm
    permission_required = 'catalog.can_mark_returned'
    
class AuthorDelete(PermissionRequiredMixin, DeleteView):
    model = Author
    success_url = reverse_lazy('authors')
    permission_required = 'catalog.can_mark_returned'

class BookCreate(PermissionRequiredMixin, CreateView):
    model = Book
    form_class = BookForm
    permission_required = 'catalog.can_mark_returned'
    
class BookUpdate(PermissionRequiredMixin, UpdateView):
    model = Book
    form_class = BookForm
    permission_required = 'catalog.can_mark_returned'
    
class BookDelete(PermissionRequiredMixin, DeleteView):
    model = Book
    success_url = reverse_lazy('books')
    permission_required = 'catalog.can_mark_returned'

@login_required
def add_review(request, pk):
    book = get_object_or_404(Book, pk=pk)
    
    if request.method == 'POST':
        form = ReviewForm(request.POST)
        
        if form.is_valid():
            review, created = Review.objects.update_or_create(
                book=book,
                user=request.user,
                defaults={
                    'rating': form.cleaned_data['rating'],
                    'comment': form.cleaned_data['comment']
                }
            )
            
            messages.success(request, '您的评论已成功提交！')
            return redirect('book-detail', pk=book.pk)
    
    return redirect('book-detail', pk=book.pk)

@login_required
@require_POST
def toggle_favorite(request, pk):
    book = get_object_or_404(Book, pk=pk)
    
    if book.favorites.filter(id=request.user.id).exists():
        book.favorites.remove(request.user)
        is_favorite = False
    else:
        book.favorites.add(request.user)
        is_favorite = True
    
    return JsonResponse({
        'status': 'success',
        'is_favorite': is_favorite,
        'total_favorites': book.total_favorites()
    })

@login_required
@require_POST
def toggle_like(request, pk):
    book = get_object_or_404(Book, pk=pk)
    
    if book.likes.filter(id=request.user.id).exists():
        book.likes.remove(request.user)
        is_liked = False
    else:
        book.likes.add(request.user)
        is_liked = True
    
    return JsonResponse({
        'status': 'success',
        'is_liked': is_liked,
        'total_likes': book.total_likes()
    })

@login_required
def profile_view(request):
    try:
        profile = request.user.profile
    except UserProfile.DoesNotExist:
        profile = UserProfile.objects.create(user=request.user)
    
    if request.method == 'POST':
        user_form = UserForm(request.POST, instance=request.user)
        profile_form = UserProfileForm(request.POST, request.FILES, instance=profile)
        
        if user_form.is_valid() and profile_form.is_valid():
            user_form.save()
            profile_form.save()
            messages.success(request, '您的个人资料已更新！')
            return redirect('profile')
    else:
        user_form = UserForm(instance=request.user)
        profile_form = UserProfileForm(instance=profile)
    
    # 获取用户收藏的书籍
    favorite_books = Book.objects.filter(favorites=request.user)
    
    # 获取用户借阅历史
    borrow_history = BorrowHistory.objects.filter(borrower=request.user).order_by('-borrow_date')
    
    context = {
        'user_form': user_form,
        'profile_form': profile_form,
        'favorite_books': favorite_books,
        'borrow_history': borrow_history,
    }
    
    return render(request, 'catalog/profile.html', context)

@login_required
def borrow_book(request, pk):
    book_instance = get_object_or_404(BookInstance, pk=pk)
    
    if book_instance.status != 'a':
        messages.error(request, '该书已被借出或不可用')
        return redirect('book-detail', pk=book_instance.book.pk)
    
    # 更新书籍实例状态
    book_instance.status = 'o'
    book_instance.borrower = request.user
    book_instance.borrow_date = datetime.date.today()
    book_instance.due_back = datetime.date.today() + datetime.timedelta(weeks=3)
    book_instance.save()
    
    # 创建借阅历史记录
    BorrowHistory.objects.create(
        book_instance=book_instance,
        borrower=request.user,
        borrow_date=datetime.date.today()
    )
    
    messages.success(request, f'您已成功借阅《{book_instance.book.title}》')
    return redirect('my-borrowed')

@login_required
@permission_required('catalog.can_mark_returned', raise_exception=True)
def return_book(request, pk):
    book_instance = get_object_or_404(BookInstance, pk=pk)
    
    if book_instance.status != 'o':
        messages.error(request, '该书未被借出')
        return redirect('all-borrowed')
    
    # 更新书籍实例状态
    book_instance.status = 'a'
    book_instance.borrower = None
    book_instance.due_back = None
    book_instance.save()
    
    # 更新借阅历史记录
    borrow_history = BorrowHistory.objects.filter(
        book_instance=book_instance,
        return_date__isnull=True
    ).first()
    
    if borrow_history:
        borrow_history.return_date = datetime.date.today()
        borrow_history.save()
    
    messages.success(request, f'《{book_instance.book.title}》已归还')
    return redirect('all-borrowed')

def book_ranking(request):
    # 评分排行
    top_rated = Book.objects.annotate(avg_rating=Avg('review__rating')).order_by('-avg_rating')[:10]
    
    # 借阅排行
    most_borrowed = Book.objects.annotate(borrow_count=Count('bookinstance__borrowhistory')).order_by('-borrow_count')[:10]
    
    # 收藏排行
    most_favorited = Book.objects.annotate(favorite_count=Count('favorites')).order_by('-favorite_count')[:10]
    
    context = {
        'top_rated': top_rated,
        'most_borrowed': most_borrowed,
        'most_favorited': most_favorited,
    }
    
    return render(request, 'catalog/book_ranking.html', context)

def recommend_books(request):
    if not request.user.is_authenticated:
        # 为未登录用户推荐评分最高的书籍
        recommended_books = Book.objects.annotate(avg_rating=Avg('review__rating')).order_by('-avg_rating')[:10]
        context = {'recommended_books': recommended_books}
        return render(request, 'catalog/recommended_books.html', context)
    
    try:
        profile = request.user.profile
    except UserProfile.DoesNotExist:
        profile = UserProfile.objects.create(user=request.user)
    
    # 基于用户阅读偏好推荐
    preferred_genres = profile.reading_preferences.all()
    
    if preferred_genres:
        # 如果用户有设置阅读偏好，根据偏好推荐
        recommended_books = Book.objects.filter(genre__in=preferred_genres).distinct().annotate(
            avg_rating=Avg('review__rating')
        ).order_by('-avg_rating')[:10]
    else:
        # 如果用户没有设置阅读偏好，根据他们的借阅历史和收藏推荐
        borrowed_books = BookInstance.objects.filter(borrower=request.user).values_list('book', flat=True)
        favorited_books = Book.objects.filter(favorites=request.user).values_list('id', flat=True)
        
        # 找出这些书的类型
        genres_from_history = Genre.objects.filter(
            Q(book__in=borrowed_books) | Q(book__in=favorited_books)
        ).distinct()
        
        if genres_from_history:
            # 推荐相同类型的其他书籍
            recommended_books = Book.objects.filter(
                genre__in=genres_from_history
            ).exclude(
                Q(id__in=borrowed_books) | Q(id__in=favorited_books)
            ).distinct().annotate(
                avg_rating=Avg('review__rating')
            ).order_by('-avg_rating')[:10]
        else:
            # 如果没有借阅历史和收藏，推荐评分最高的书籍
            recommended_books = Book.objects.annotate(avg_rating=Avg('review__rating')).order_by('-avg_rating')[:10]
    
    context = {'recommended_books': recommended_books}
    return render(request, 'catalog/recommended_books.html', context)

def register(request):
    """用户注册视图"""
    if request.method == 'POST':
        form = RegisterForm(request.POST)
        if form.is_valid():
            user = form.save()
            # 创建关联的用户个人资料
            UserProfile.objects.create(user=user)
            messages.success(request, '注册成功！现在您可以登录了。')
            return redirect('login')
    else:
        form = RegisterForm()
    
    return render(request, 'registration/register.html', {'form': form})
